package drds.plus.sql_process.optimizer.cost_esitimater;

import drds.plus.sql_process.abstract_syntax_tree.configuration.IndexMapping;
import drds.plus.sql_process.abstract_syntax_tree.expression.bind_value.BindValue;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.Filter;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.Operation;
import drds.plus.sql_process.abstract_syntax_tree.node.query.$Query$;
import drds.plus.sql_process.abstract_syntax_tree.node.query.Query;
import drds.plus.sql_process.abstract_syntax_tree.node.query.TableQuery;
import drds.plus.sql_process.optimizer.OptimizerContext;
import drds.plus.sql_process.optimizer.cost_esitimater.statistics.TableIndexStatisticsItem;
import drds.plus.sql_process.optimizer.cost_esitimater.statistics.TableStatistics;
import drds.plus.sql_process.utils.DnfFilters;

import java.util.List;

public class QueryNodeCostEstimater implements CostEstimater {

    public Cost estimate(Query query) {
        Cost cost = new Cost();

        long initRowCount = 0;
        long keyFilteredCount = 0;
        long keyFilteredAndValueFilteredCount = 0;
        boolean dependentOnOtherQuery = false;
        // 索引
        IndexMapping indexMapping = null;
        // 索引的选择度
        TableIndexStatisticsItem tableIndexStatisticsItem = null;
        // step1.估算行数
        if (query instanceof $Query$) {
            // 查询对象是另一个查询，说明数据是on fly的，根据子查询提供的行数来确定初始行数
            Cost subCost = CostEsitimaterFactory.estimate((($Query$) query).getFirstSubNodeQueryNode());
            initRowCount = subCost.getKeyFilteredAndValueFilteredCount();
            dependentOnOtherQuery = true;
        } else if (query instanceof TableQuery) {
            // 查询对象是一个物理表，则根据表的统计信息来获取初始行数
            dependentOnOtherQuery = false;
            indexMapping = ((TableQuery) query).getIndexMappingUsed();
            TableStatistics tableStatistics = OptimizerContext.getOptimizerContext().getStatisticsManager().getTableStatistics(((TableQuery) query).getTableMetaData().getTableName());
            tableIndexStatisticsItem = OptimizerContext.getOptimizerContext().getStatisticsManager().getIndexStatistics(indexMapping.getIndexName());
            if (tableStatistics != null) {
                initRowCount = tableStatistics.getRowCount();
            } else {
                initRowCount = 10000;// 一万以内吧(最开始建的表不会超过10000条数据,如果是交易数据还是容易达到的)
            }
        }

        List<Filter> keyFilterList = DnfFilters.toDnfFilterList(query.getIndexQueryKeyFilter());
        List<Filter> valueFilterList = DnfFilters.toDnfFilterList(query.getResultFilter());

        // 主键是唯一的，如果在主键上进行了=操作，最后结果肯定不超过1
        // 对于唯一的列也是同理，但是现在还不支持
        // TODO:暂时没有考虑倒排索引
        if (this.isAllEqualOrIs(keyFilterList) && indexMapping != null && indexMapping.isPrimaryKeyIndex()) {
            keyFilteredCount = 1;
            keyFilteredAndValueFilteredCount = 1;
        } else if (query.getLimitFrom() != null && query.getLimitTo() != null) {
            keyFilteredCount = CostEsitimaterFactory.estimateRowCount(initRowCount, keyFilterList, indexMapping, tableIndexStatisticsItem);

            Object from = query.getLimitFrom();
            if (from instanceof BindValue) {
                from = ((BindValue) from).getValue();
            }
            Object to = query.getLimitTo();
            if (to instanceof BindValue) {
                to = ((BindValue) to).getValue();
            }
            // 对于包含limit的查询，使用limit提供的结果
            if (from instanceof Long && to instanceof Long) {
                keyFilteredAndValueFilteredCount = ((Long) from - (Long) to);
            }
        } else if (query.getLimitFrom() != null || query.getLimitTo() != null) {
            keyFilteredCount = CostEsitimaterFactory.estimateRowCount(initRowCount, keyFilterList, indexMapping, tableIndexStatisticsItem) / 2;
            keyFilteredAndValueFilteredCount = keyFilteredCount;
            keyFilteredAndValueFilteredCount = CostEsitimaterFactory.estimateRowCount(keyFilteredAndValueFilteredCount, valueFilterList, indexMapping, tableIndexStatisticsItem);
        } else {
            // 对于其他情况，则根据约束条件进行推算
            keyFilteredCount = CostEsitimaterFactory.estimateRowCount(initRowCount, keyFilterList, indexMapping, tableIndexStatisticsItem);
            keyFilteredAndValueFilteredCount = keyFilteredCount;
            keyFilteredAndValueFilteredCount = CostEsitimaterFactory.estimateRowCount(keyFilteredAndValueFilteredCount, valueFilterList, indexMapping, tableIndexStatisticsItem);
        }

        long networkTransferCount = 0;
        // step2.估计网络开销
        if (dependentOnOtherQuery) {
            if (query.getDataNodeId() == null || (query.getDataNodeId().equals((($Query$) query).getFirstSubNodeQueryNode().getDataNodeId()))) {
                // 如果当前的查询和子查询在一台机器上执行，则网络开销为0
                networkTransferCount = 0;
            } else {
                // dependentOnOtherQuery:if (query instanceof $Query$) {
                // 如果当前的查询和子查询不在一台机器上，则需要将子查询的数据传输到当前查询的机器上
                // 所以网络开销就为子查询结果的行数
                // （目前只用行数作为开销的依据，没有考虑字段的大小等复杂因素）
                networkTransferCount = initRowCount;
            }
        } else {
            // 如果是对物理表进行查询，则不需要经过网络传输，网络开销为0
            networkTransferCount = 0;
        }
        cost.setKeyFilteredCount(keyFilteredCount);
        cost.setKeyFilteredAndValueFilteredCount(keyFilteredAndValueFilteredCount);
        cost.setNetworkTransferCount(networkTransferCount);
        return cost;
    }

    private boolean isAllEqualOrIs(List<Filter> filterList) {
        if (filterList == null || filterList.isEmpty()) {
            return false;
        }

        for (Filter filter : filterList) {
            if (filter.getOperation() == Operation.is && filter.getOperation() != Operation.equal) {
                return false;
            }
        }
        return true;
    }

}
